/*
 * Copyright 2002-2006 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package de.riceman.simpleGo.view.views;

import java.awt.BorderLayout;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.text.DefaultCaret;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.richclient.application.support.AbstractView;

import de.riceman.simpleGo.SimpleGo;
import de.riceman.simpleGo.events.SimpleGoLifecycleApplicationEvent;
import de.riceman.simpleGo.main.BitMatrix;
import de.riceman.simpleGo.main.GoGame;
import de.riceman.simpleGo.players.Player;

/**
 * This class defines the initial view to be presented in the SimpleGo application. It is
 * constructed automatically by the platform and configured according to the bean
 * specification in the application context.
 * 
 * @author Larry Streepy
 * 
 */
public class GameView extends AbstractView implements ApplicationListener {

	private static final Log logger = LogFactory.getLog(GameView.class);
	
	private GoGame goGame;
	private JScrollPane scrollPane;
	private JTextArea console;
    /**
     * Create the actual UI control for this view. It will be placed into the window
     * according to the layout of the page holding this view.
     */
    protected JComponent createControl() {
        // In this view, we're just going to use standard Swing to place a
        // few controls.

    	console = new JTextArea();
    	console.setEditable(false);
    	console.setAutoscrolls(true);
    	
    	DefaultCaret caret = (DefaultCaret) console.getCaret();
    	caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
    	
    	scrollPane = new JScrollPane(console, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);


        JPanel panel = getComponentFactory().createPanel(new BorderLayout());
        panel.add(scrollPane);

        return panel;
    }

	@Override
	public void onApplicationEvent(ApplicationEvent event) {

		if (event instanceof SimpleGoLifecycleApplicationEvent) {
			
			StringBuffer out = new StringBuffer();
			
			SimpleGoLifecycleApplicationEvent lcae = (SimpleGoLifecycleApplicationEvent) event;
			
			//Display game statistics upon change
			if (lcae.getEventType() == SimpleGoLifecycleApplicationEvent.INITIALIZED && lcae.objectIs(GoGame.class)) {
		    	goGame = (GoGame) lcae.getObject();

		    	update(out);		    
		    }
			
			if (lcae.getEventType() == SimpleGoLifecycleApplicationEvent.MOVE_EXPECTED && lcae.objectIs(Player.class)) {
				
				Player player = (Player) lcae.getObject();
				
				if (logger.isInfoEnabled()) {
					logger.info("GameView received MOVE_EXPECTED.");
				}
				out.append("\n__________________________\nMOVE No. " + goGame.getMoveCount() + "\n");
				
				if (player.getPlayer()) {
					out.append("dark player's turn> ");
				} else {
					out.append("light player's turn> ");
				}
			}

			if ((lcae.getEventType() == SimpleGoLifecycleApplicationEvent.PASSED && lcae.objectIs(BitMatrix.class)) ||
					(lcae.getEventType() == SimpleGoLifecycleApplicationEvent.MOVED && lcae.objectIs(BitMatrix.class))	) {

				BitMatrix move = (BitMatrix) lcae.getObject();
				
		    	out.append(getCoordinate(move));
		    	
		    	update(out);
		    }
			
			if (lcae.getEventType() == SimpleGoLifecycleApplicationEvent.FINISHED && lcae.objectIs(GoGame.class)) {
		    	goGame = (GoGame) lcae.getObject();

		    	out.append("PASSED - Game finished.\nDark player's result: ");
		    	
		    	out.append(Integer.toString(goGame.getConfiguration().getDarksCaptured()) + " captured enemy stones.");
		    	
		    	out.append(Integer.toString(goGame.getConfiguration().getValueOfCapturedPartitions(true)) + " captured points.");
		    	
		    	int totalValueOfDark = goGame.getConfiguration().getDarksCaptured() 
		    							+ goGame.getConfiguration().getValueOfCapturedPartitions(true);
		    	out.append("Total: " + Integer.toString(totalValueOfDark) + "\n");
		    	
		    	out.append("Light player's result: " + Integer.toString(goGame.getConfiguration().getLightsCaptured()) + " captured enemy stones.");
		    	
		    	out.append(Integer.toString(goGame.getConfiguration().getValueOfCapturedPartitions(false)) + " captured points.");
		    	
		    	int totalValueOfLight = goGame.getConfiguration().getLightsCaptured() 
		    							+ goGame.getConfiguration().getValueOfCapturedPartitions(false);
		    	out.append("Total: " + Integer.toString(totalValueOfLight) + "\n");
		    	
		    	if (totalValueOfLight > totalValueOfDark) {
		    		out.append("Light wins by " + Integer.toString(totalValueOfLight - totalValueOfDark));
		    	}
		    	if (totalValueOfLight < totalValueOfDark) {
		    		out.append("Dark wins by " + Integer.toString(totalValueOfDark - totalValueOfLight));
		    	}
		    	if (totalValueOfLight == totalValueOfDark) {
		    		out.append("They're both losers ;-D");
		    	}
		    }
			
			if (lcae.getEventType() == SimpleGoLifecycleApplicationEvent.ILLEGALMOVE && lcae.objectIs(GoGame.class)) {
		    	goGame = (GoGame) lcae.getObject();

		    	out.append(" illegal move!\n");
		    }
			
			console.append(out.toString());
		}
	}

	private void update(StringBuffer out) {
		
		//display last move
		/*if (goGame.getMove() instanceof BitMatrix) {
			console.append(getCoordinate(goGame.getMove()) + "\n");
		}*/
		//display game statistics
		
		Iterator<BitMatrix> it;
		
		out.append("Partitions of the dark player:\n");

		Iterator<BitMatrix> it2;
		it = goGame.getConfiguration().getDarkPartitions().iterator();
		
		while (it.hasNext()) {
			BitMatrix next = it.next();
			out.append(next + " Libs: " + Integer.toString(
					goGame.getConfiguration().getLibertiesOfPartition(next).getNumberOfSetBits()) + "\n");
			
			it2 = next.getChildren().iterator();
			
			while (it2.hasNext()) {
				out.append("real eye: " + it2.next() + "\n");
			}
		}
		out.append("unreal eyes of the dark player:\n");
		
		it = goGame.getConfiguration().getDarksCapturedPartitions().iterator();
		
		while (it.hasNext()) {
			out.append(it.next().toString() + "\n");
		}
		
		out.append("Partitions of the light player: \n");
		
		
		it = goGame.getConfiguration().getLightPartitions().iterator();
		
		while (it.hasNext()) {
			BitMatrix next = it.next();
			out.append(next + " Libs: " + Integer.toString(
					goGame.getConfiguration().getLibertiesOfPartition(next).getNumberOfSetBits()) + "\n");
			
			it2 = next.getChildren().iterator();
			
			while (it2.hasNext()) {
				out.append("owned partition: " + it2.next() + "\n");
			}
			
		}
		
		out.append("unreal eyes of the light player: \n");
		
		it = goGame.getConfiguration().getLightsCapturedPartitions().iterator();
		
		while (it.hasNext()) {
			out.append(it.next().toString() + "\n");
		}
		
		out.append("clear partitions: \n");
		
		//AbstractSet<BitMatrix> b = config.initClearPartitions();
		it = goGame.getConfiguration().getClearPartitions().iterator();
		
		while (it.hasNext()) {
			out.append(it.next().toString() + "\n");
		}
		
		out.append("\nposition table: " + goGame.getConfiguration().getHistory().toString());

		//out.append("\ndarks value: " + goGame.getConfiguration().getConfigurationValue(true));
		
		//out.append("\nlights value: " + goGame.getConfiguration().getConfigurationValue(false) + "\n");
		
		if (goGame.getConfiguration().getPlayersTurn()) {
			out.append("dark player will move next. regular moves:\n");			
		} else {
			out.append("light player will move next. regular moves:\n");						
		}
		out.append(goGame.getConfiguration().getRegularMoves(goGame.getConfiguration().getPlayersTurn()) + "\n");

	}

	/**
	 * @param move
	 * @return the coordinate as a readable String
	 */
	private String getCoordinate(BitMatrix move) {
		// TODO Auto-generated method stub
		int i = move.getIndexOfFirstSetBit();
		int a;
		
		if (i == -1) {
			return "PASSED\n";
		}
		
		a = i / goGame.getConfiguration().getSize();
		i = i % goGame.getConfiguration().getSize();
		
		return "(" + Integer.toString(a) + "/" + Integer.toString(i) + ")\n";
	}
}
